/**
 * Copyright (C) 2008 Christopher Allen Ogden
 *
 *     This file is part of Odysi.
 *
 *  Odysi is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  Odysi is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with Odysi.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "mobile.h"
#ifndef SERVER
#include "renderSystem.h"
#endif
#include "log.h"
#include "animationListManager.h"

/**
 * Stores information about a character.
 *
 * @author Ogden, Chris
 */
class Character:public Mobile
{
    public:
        // Animations.
        enum {NORTH, EAST, SOUTH, WEST, NORTH_WALK, EAST_WALK, SOUTH_WALK, WEST_WALK};

        Character():_animation(0),_stillTicks(0) {}

        /**
         * Set the animation list.
         *
         * @param al    Animation list.
         */
        void setAnimationList(const AnimationList &al) { _al = al; }

        /**
         * Draw the object.
         */
        inline virtual void draw(int x, int y, float alpha = 1.0f) const
        {
#ifndef SERVER
            RenderSystem::GS().color(getRed(), getGreen(), getBlue(), getAlpha() * alpha);
            Location loc(getLocation());
            TileManager::GS().drawTile(LEVEL_CHARACTERS, getTileID(), getCurrentFrame(), x + loc.getXOff(), y + loc.getYOff() - loc.getZ());
            RenderSystem::GS().color();
#endif
        }

        /**
         * Determine if the object is walkable.
         *
         * @return  An integer bitmap of the walkable attributes.
         */
        inline virtual int getWalkable(void) const
        {
            return TileManager::GS().getTile(LEVEL_CHARACTERS, getTileID())->getWalkable();
        }

        /**
         * Get the height of the object.
         *
         * @return  The height of the object.
         */
        inline virtual unsigned int getHeight(void) const
        {
            return TileManager::GS().getTile(LEVEL_CHARACTERS, getTileID())->getHeight();
        }

        /**
         * Move to relative x and y coordinates.
         *
         * @param xOff  The relative X coordinate.
         * @param yOff  The relative Y coordinate.
         * @param zOff  The relative Z coordinate.
         */
        inline virtual void move(float xOff, float yOff, float zOff = 0)
        {
            Mobile::move(xOff, yOff, zOff);
            if(xOff > 0) 
            {
                if(_animation != EAST_WALK) _animation = EAST;
            }
            else if(xOff < 0)
            {
                if(_animation != WEST_WALK) _animation = WEST;
            }
            else if(yOff > 0)
            {
                if(_animation != SOUTH_WALK) _animation = SOUTH;
            }
            else if(yOff < 0)
            {
                if(_animation != NORTH_WALK) _animation = NORTH;
            }
        }

        /**
         * Cause the character to face a certain
         * direction, given an offset.
         *
         * @param xOff  The X offset.
         * @param yOff  The Y offset.
         */
        inline virtual void face(float xOff, float yOff)
        {
            // Don't allow facing if moving.
            if(_stillTicks < 2) return;

            int prevAnimation = _animation;
            if(xOff > 0) _animation = EAST;
            else if(xOff < 0) _animation = WEST;
            else if(yOff > 0) _animation = SOUTH;
            else if(yOff < 0) _animation = NORTH;
            if(prevAnimation != _animation) setTileID(_al[_animation]);
        }

        /**
         * Update the object.
         */
        virtual void tick(void)
        {
            Mobile::tick();

            if(!isMoving()) _stillTicks++;
            else _stillTicks = 0;

            int prevAnimation = _animation;
            if(_stillTicks < 5)
            {
                switch(_animation)
                {
                    case NORTH:
                        _animation = NORTH_WALK;
                        break;
                    case SOUTH:
                        _animation = SOUTH_WALK;
                        break;
                    case EAST:
                        _animation = EAST_WALK;
                        break;
                    case WEST:
                        _animation = WEST_WALK;
                        break;
                }
            }
            else
            {
                switch(_animation)
                {
                    case NORTH_WALK:
                        _animation = NORTH;
                        break;
                    case SOUTH_WALK:
                        _animation = SOUTH;
                        break;
                    case EAST_WALK:
                        _animation = EAST;
                        break;
                    case WEST_WALK:
                        _animation = WEST;
                        break;
                }
            }

            if(prevAnimation != _animation) setTileID(_al[_animation]);
        }

        inline int getMobID(void) const { return _mobID; }
        inline void setMobID(int mobID) {
            _al = AnimationListManager::GS().getAnimationList(mobID);
            _mobID = mobID;
        }

    private:
        int _mobID;         // Mobile ID
        int _animation;     // The current animation.
        AnimationList _al;  // The animation list.
        int _stillTicks;    // Still ticks.
};
